using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Data;
using System.Data.OleDb;

namespace Dbam.DbFramework.Tests
{
    [TestFixture]
	public class SqlDbFactoryTests
	{
		[SetUp]
		public void SetupTest()
		{
			string cmdText = "Delete From [Accounts] Where 1 = 1";
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			dbFactory.CreateCommand(cmdText).ExecuteNonQuery();
		}

        [Test]
        public void ConnectDisconnectTest()
        {
            SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
            dbFactory.Disconnect();
        }

		[Test]
		public void ConnectDisconnectTwiceTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			dbFactory.Disconnect();
			dbFactory.Disconnect();
		}

		[Test]
		[ExpectedException(typeof(InvalidOperationException))]
		public void ConnectTwiceTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			dbFactory.Connect(TestSettings.Default.TestDbConnectionString);
		}

		[Test]
		public void CreateCommandAfterDisconnectTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			dbFactory.Disconnect();
			IDbCommand command = dbFactory.CreateCommand("select * from [Accounts]");
		}

		[Test]
		public void CreateAndSelectTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			ObjectRelationalMapper<AccountEntity> orm = new ObjectRelationalMapper<AccountEntity>(dbFactory);

			for(int index = 1; index <= 5; index++)
			{
				AccountEntity account = new AccountEntity();
				account.Name = string.Format("User {0}", index);
				account.AccountId = new Guid(string.Format("00000000-0000-0000-0000-00000000000{0}", index));
				account.LastLogon = DateTime.Now;
				account.OpenDate = DateTime.Parse(@"1/1/2000");
				orm.Insert(account);

				AccountEntity fetchedEntity = new AccountEntity();
				fetchedEntity.AccountId = new Guid(string.Format("00000000-0000-0000-0000-00000000000{0}", index));
				orm.Select(fetchedEntity);
				Assert.AreEqual(account.AccountId, fetchedEntity.AccountId);
				Assert.AreEqual(account.Name, fetchedEntity.Name);
				Assert.AreEqual(account.LastLogon.Value.ToShortDateString(), fetchedEntity.LastLogon.Value.ToShortDateString());
				Assert.AreEqual(account.OpenDate, fetchedEntity.OpenDate);
			}
		}

		[Test]
		public void DeleteEntityOnConnectionClosedTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			ObjectRelationalMapper<AccountEntity> orm = new ObjectRelationalMapper<AccountEntity>(dbFactory);
			AccountEntity account = new AccountEntity();
			account.Name = string.Format("User 1");
			account.AccountId = Guid.NewGuid();
			account.LastLogon = DateTime.Now;
			account.OpenDate = DateTime.Parse(@"1/1/2000");
			orm.Insert(account);
			dbFactory.Disconnect();
			orm.Delete(account);
		}

		[Test, ExpectedException(typeof(ArgumentException))]
		public void SelectNonExistentEntityTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			ObjectRelationalMapper<AccountEntity> orm = new ObjectRelationalMapper<AccountEntity>(dbFactory);
			AccountEntity account = new AccountEntity();
			Assert.IsFalse(orm.Exists(account));
			orm.Select(account);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void InvalidSelectCommandTypeTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			IDataAdapter adp = dbFactory.CreateAdapter(new OleDbCommand(), null, null, null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void InvalidInsertCommandTypeTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			IDataAdapter adp = dbFactory.CreateAdapter(null, new OleDbCommand(), null, null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void InvalidUpdateCommandTypeTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			IDataAdapter adp = dbFactory.CreateAdapter(null, null, new OleDbCommand(), null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void InvalidDeleteCommandTypeTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			IDataAdapter adp = dbFactory.CreateAdapter(null, null, null, new OleDbCommand());
		}

		[Test]
		public void TryDeleteEntityOnClosedConnectionTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			ObjectRelationalMapper<AccountEntity> orm = new ObjectRelationalMapper<AccountEntity>(dbFactory);
			dbFactory.Disconnect();
			orm.Delete(new AccountEntity());
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TryDeleteNullEntityTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			ObjectRelationalMapper<AccountEntity> orm = new ObjectRelationalMapper<AccountEntity>(dbFactory);
			orm.Delete(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TryConnectWithNullAndEmptyConnectionString()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(null);
			dbFactory = new SqlDbFactory(string.Empty);
		}

		[Test]
		[ExpectedException(typeof(ApplicationException))]
		public void TryConnectWithInvalidConnectionStringTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory("data source=dbam-mac; database=dbnoexist");
		}

		[Test]
		public void AddParamsTest()
		{
			SqlDbFactory dbFactory = new SqlDbFactory(TestSettings.Default.TestDbConnectionString);
			IDbCommand cmd = dbFactory.CreateCommand("select * from something");
			dbFactory.AddInputParam(cmd, "param1", DbType.Int32, 1);
			dbFactory.AddOutputParam(cmd, "param2", DbType.String, "test");
			dbFactory.AddInputOutputParam(cmd, "param3", DbType.Guid, Guid.NewGuid());
			dbFactory.AddReturnValueParam(cmd, "param4", DbType.Int32, null);

			Assert.IsNotNull(cmd.Parameters["param1"]);
			Assert.IsNotNull(cmd.Parameters["param2"]);
			Assert.IsNotNull(cmd.Parameters["param3"]);
			Assert.IsNotNull(cmd.Parameters["param4"]);
		}
	}
}